#include <gtk/gtk.h>
#include <regex.h>
#include <sys/types.h>

extern GtkWidget *mainWindowApp; /* Declared in main.c */

#define MASTER_SEARCH_DATA "search1" /* Storage for the Phase One data inside the g_object */
#define MASTER_SEARCH_CONTROL "control1" /* Storage for the Phase One data inside the g_object */
#define MASTER_STATUSBAR_DATA "status1" /* Storage for the Phase One data inside the g_object */
#define MASTER_OPTIONS_DATA "options1" /* Storage for the Phase One data inside the g_object */
#define OPTIONS_SAVE_FOLDER PACKAGE
#define OPTIONS_SAVE_LOCATION PACKAGE "/config.ini"
#define CELL_TEXT_RENDERER "renderer"
#define TEST_REGEX "testRegExPtr"
#define miniBuf 3 /* Size of regular expression interim strings */
#define TREEVIEW_HEADER_PIXEL_SIZE_Y 25 /* Treeview header size in pixels */

#define GET_LAST_PTR(x) g_ptr_array_index(x, (x->len - 1))
#define DEL_LAST_PTR(x) g_ptr_array_remove_index(x, (x->len -1))
#define STATUSBAR_CONTEXT_ID(x) (gtk_statusbar_get_context_id(x, MASTER_STATUSBAR_DATA))

#define MAX_DIRECTORY_WALK_DEPTH 256
#define MAX_FILENAME_STRING 512
#define MAX_STRING_SIZE 512
#define MAX_SUB_MATCHES 4
#define MAX_MATCHES 256

#define FORCED_DELAY_USLEEP_TIME 2500000
#define SPIN_BAR_USLEEP_TIME 100000
#define CONFIG_DISABLE_SAVE_CONFIG 1 /* Used by config->restart to check for reset */

#define MAX_FILE_LIST_SIZE 3 /* Maximum number of exe names in browserList. Used by STEP_VAL */
#define MIN_STEP_VAL (1 / (EXE_LIST_LEN * (MAX_FILE_LIST_SIZE + 1))) /* Minimum amount to move progress bar by when finding executables */
typedef enum {
  BROWSER_LIST = 0,
  TEXTEDITOR_LIST,
  FILEEXPLORER_LIST,
  EXE_LIST_LEN
} syscallType;

enum {
    REGWIZ_NONE=-1,
    REGWIZ_DONT_KNOW,
    REGWIZ_ANY_CHAR,
    REGWIZ_THE_CHAR,
    REGWIZ_ANY_ONE_CHAR,
    REGWIZ_ANY_CHAR_EXCEPT,
    REGWIZ_THE_PHRASE,
    REGWIZ_SPACE,
    REGWIZ_ANY_NUMERIC,
    REGWIZ_ANY_TEXT,
    REGWIZ_START_TYPE,
    REGWIZ_END_TYPE
};

enum
{
   REGEX_TYPE_COLUMN,
   REGEX_ENTRY_COLUMN,
   REGEX_REPEAT_COLUMN,
   REGEX_TYPE_INT_COLUMN,
   REGEX_REPEAT_INT_COLUMN,
   REGEX_N_COLUMNS
};

enum {
    REGWIZ_REPEAT_ONCE=0,
    REGWIZ_REPEAT_ONE_PLUS,
    REGWIZ_REPEAT_ZERO_PLUS,
    REGWIZ_REPEAT_ZERO_ONE
};

enum {
    FILE_REGEX_TYPE=1,
    CONTEXT_REGEX_TYPE
};

typedef struct
{
  gchar constantString[MAX_FILENAME_STRING + 1];
  GStringChunk *statusbarChunk; /* Mass storage for all of the directory locations */
} statusbarData;

typedef struct
{
    gsize matchIndex; /* first lineMatch index */
    gsize matchCount; /* Number of lineMatch items */
    gchar *pFullName; /* pointer to the full name */
    gchar *pFileName; /* pointer to the file name */
    gchar *pLocation; /* pointer to the location */
    gchar *pMDate; /* pointer to the modified date */
    gchar *pFileSize; /* pointer to the file size */
    gchar *pFileType; /* pointer to the file size */
    long int mDate; /* modified date as an integer */
    unsigned int fileSize; /* filesize as an integer */
} textMatch;

typedef struct 
{
    gsize lineNum;
    gsize lineCount; /* Number of lines within this match */
    gchar *pLine; /* Copy of the line (NULL terminated) */
    gsize offsetStart; /* Match offset start */
    gsize offsetEnd; /* Match offset end */
    gsize lineLen; /* Size of pLine */
    guint invMatchIndex; /* inverse pointer to textMatch array */
} lineMatch;

typedef struct
{
  GPtrArray *pLocationArray; /* pointer to actual location chunk */
  GPtrArray *textMatchArray; /* array of text match arrays */
  GPtrArray *fileNameArray; /* array of file names */
  GPtrArray *fullNameArray; /* array of full file names */
  GPtrArray *lineMatchArray; /* array of lineMatch objects */
  
  GStringChunk *locationChunk; /* Mass storage for all of the directory locations */
  GStringChunk *fileSizeChunk; /* Mass storage for all of the file sizes */
  GStringChunk *mDateChunk; /* Mass storage for all of the modified dates */
  GStringChunk *fileTypeChunk; /* Mass storage for all of the file types */
  GStringChunk *textMatchChunk; /* Mass storage for all of the matched lines */
  
  GtkListStore *store; /* Pointer to the data store */ 
  GtkTreeIter *iter; /* Malloc Iter */
} searchData;

enum searchFlagsEnum  {
  SEARCH_SUB_DIRECTORIES = 1,
  SEARCH_CASE_SENSITIVE = (1<<1),
  SEARCH_HIDDEN_FILES = (1<<2),
  SEARCH_SKIP_LINK_FILES = (1<<3),
//  SEARCH_EXTENDED_REGEX = (1<<4),
  SEARCH_TEXT_CONTEXT = (1<<5),
  SEARCH_INVERT_FILES = (1<<6),
  SEARCH_MORETHAN_SET = (1<<7),
  SEARCH_LESSTHAN_SET = (1<<8),
  SEARCH_AFTER_SET = (1<<9),
  SEARCH_BEFORE_SET = (1<<10)
};

enum callerIdList {
  FILE_NAME_CID = 1,
  CONTAINING_TEXT_CID,
  LOOK_IN_CID,
  FILE_NAME_OPTIONS_CID,
  CONTAINING_OPTIONS_CID
};

typedef struct
{
  gchar *startingFolder; /* Pointer to the starting location */
  gchar *fileSearchRegEx; /* Regular expression pointer for the file search */
  gchar *textSearchRegEx; /* Regular expression pointer for the text search */
  guint fileSearchFlags; /* Flags for the file regexp */
  guint textSearchFlags; /* Flags for the text regexp */
  GtkStatusbar *status; /* Pointer to the statusbar */
  GtkTreeView *listView; /* Pointer to the list view widget */
  GtkTextView *textView; /* Pointer to the text view widget */
  GtkButton *goButton; /* Pointer to the start button */
  GtkButton *stopButton; /* Pointer to the stop button */
  GtkButton *goButton1; /* Pointer to the start button */
  GtkButton *stopButton1; /* Pointer to the stop button */
  GtkWidget *goButton2; /* Pointer to the start button */
  GtkWidget *stopButton2; /* Pointer to the stop button */
  time_t after;
  time_t before;
  off_t moreThan;
  off_t lessThan;
  enum searchFlagsEnum flags;
  gboolean cancelSearch; /* True stops the current search ASAP */
} searchControl;

typedef struct
{
    gchar *control;
    gsize length;
    regex_t *regExpr;
} control2;

enum  {
  FILENAME_COLUMN = 0,
  LOCATION_COLUMN,
  SIZE_COLUMN,
  TYPE_COLUMN,
  MODIFIED_COLUMN, 
  MATCHES_COUNT_STRING_COLUMN,
  FULL_FILENAME_COLUMN,
  INT_SIZE_COLUMN,
  INT_MODIFIED_COLUMN,
  MATCHES_COUNT_COLUMN,
  MATCH_INDEX_COLUMN,
  N_COLUMNS
};

/* Seach library functions */
void *walkDirectories(void *args);
glong phaseOneSearch(searchControl *mSearchControl, searchData *mSearchData, statusbarData *status);
glong phaseTwoSearch(searchControl *mSearchControl, searchData *mSearchData, statusbarData *status);
gboolean getAllMatches(searchData *mSearchData, gchar *contents, gsize length, regex_t *search);
void dereferenceAbsolutes(searchData *mSearchData,gchar *contents, gsize length);
void getLength(searchData *mSearchData, textMatch *newMatch);
void getFileType(searchData *mSearchData, textMatch *newMatch);
void getModified(searchData *mSearchData, textMatch *newMatch);
void getFileSize(searchData *mSearchData, textMatch *newMatch);
void displayMatch(searchControl *mSearchControl, searchData *mSearchData);
void updateStatusFilesFound(const gsize matchCount, statusbarData *status, searchControl *mSearchControl);
gboolean statMatchPhase(const gchar *tmpFullFileName, searchControl *mSearchControl);

/* Constructors and destructors */
void createSearchData(GObject *object, const gchar *dataName);
void destroySearchData(gpointer data);
void createSearchControl(GObject *object, const gchar *dataName);
void createStatusbarData(GObject *object, const gchar *dataName);
void destroyStatusbarData(gpointer data);
void createGKeyFile(GObject *object, const gchar *dataName);
void destroyGKeyFile(gpointer data);

/* Library helpers */
void start_search_thread(GtkWidget *widget);
void stop_search_thread(GtkWidget *widget);
void set_text_ok(GtkWidget *widget);
void set_text_error(GtkWidget *widget);
gboolean test_regex(gchar *search, guint testFlags);

void initTextView( GtkTextView *widget);
void initTreeView(GtkTreeView *widget);
void tree_selection_changed_cb (GtkTreeSelection *selection, gpointer data);
void undo_popup_menu(GtkWidget *attach_widget, GtkMenu *menu);
void do_popup_menu (GtkWidget *widget, GdkEventButton *event);
void detachMenu(GtkMenuItem *menuitem);
gchar *getFullFileName(GtkTreeView *treeView, gint columnNumber);
void displayQuickMatch(searchControl *mSearchControl, searchData *mSearchData);

GKeyFile *getGKeyFile(GtkWidget *widget);
void storeGKeyFile(GKeyFile *keyString);
void statFile(const gchar *filename, gchar *date, gchar *size, gchar *type);
void openUrlLinkFunc (GtkAboutDialog *about, const gchar *link, gpointer data);

/* Save to ini helper functions */
void realizeTreeview(GtkWidget *widget, GKeyFile *keyString, const gchar *group, const gchar *name, gboolean autoColumnWidth);
void unrealizeTreeview(GtkWidget *widget, GKeyFile *keyString, const gchar *group, const gchar *name, gboolean autoColumnWidth);
void realizeTextviewFont(GtkWidget *widget, GKeyFile *keyString, const gchar *group, const gchar *name);
void unrealizeTextviewFont(GtkWidget *widget, GKeyFile *keyString, const gchar *group, const gchar *name);
void realizeTextviewHighlight(GtkWidget *widget, GKeyFile *keyString, const gchar *group, const gchar *name);
void unrealizeTextviewHighlight(GtkWidget *widget, GKeyFile *keyString, const gchar *group, const gchar *name);
void realizeMenuCheck(GtkWidget *widget, GKeyFile *keyString, const gchar *group, const gchar *name);
void unrealizeMenuCheck(GtkWidget *widget, GKeyFile *keyString, const gchar *group, const gchar *name);
void realizeMenuRadio(GtkWidget *widget, GKeyFile *keyString, const gchar *group, const gchar *name);
void unrealizeMenuRadio(GtkWidget *widget, GKeyFile *keyString, const gchar *group, const gchar *name);
void realizeCombo(GtkWidget *widget, GKeyFile *keyString, const gchar *group, const gchar *name);
void unrealizeCombo(GtkWidget *widget, GKeyFile *keyString, const gchar *group, const gchar *name);
void realizeString(GtkWidget *widget, GKeyFile *keyString, const gchar *group, const gchar *name);
void unrealizeString(GtkWidget *widget, GKeyFile *keyString, const gchar *group, const gchar *name);
gboolean realizeFileButton(GtkWidget *widget, GKeyFile *keyString, const gchar *group, const gchar *name);
void unrealizeFileButton(GtkWidget *widget, GKeyFile *keyString, const gchar *group, const gchar *name);
void realizeToggle(GtkWidget *widget, GKeyFile *keyString, const gchar *group, const gchar *name);
void unrealizeToggle(GtkWidget *widget, GKeyFile *keyString, const gchar *group, const gchar *name);
void realizeNotebook(GtkWidget *widget, GKeyFile *keyString, const gchar *group, const gchar *name);
void unrealizeNotebook(GtkWidget *widget, GKeyFile *keyString, const gchar *group, const gchar *name);
gint stringCompareFunc (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data);
gboolean addUniqueRow(GtkWidget *comboBox, const gchar *entry);
void initComboBox(GtkWidget *comboBox);
void clearComboBox(GtkWidget *comboBox);
const gchar *regexErrorDisplay(gint errorCode);
void refreshTestResults(GtkWidget *widget);
void updateTypeChangeEntry(GtkComboBox *comboBox, GtkWidget *entry, GtkWidget *repeat);
void updateRegExWizard(GtkWidget *widget);
gchar *makeInterimRegex(GtkComboBox *type, GtkEntry *entry, GtkComboBox *repeat, gint position);
gchar *convertRegex(const gchar *input, gboolean change);
gchar *convertRegex2(const gchar *input, gboolean change);
void appendTableRow(GtkWidget *widget, gint num, ...);
gchar *makeInterimRegex2(GtkWidget *widget, gint type, const gchar *pEntry, gint repeatc, gint position);
gchar *resultsToCsvString(GtkWidget *widget);
void saveResults(GtkWidget *widget);
void deleteFile(GtkWidget *widget);
void copyFile(GtkWidget *widget);
gboolean g_file_get_contents2 (const gchar *filename, gchar **contents,  gsize *length, GError **error);
gboolean g_file_set_contents2 (const gchar *filename, const gchar *contents, gssize length, GError **error);
void set_internal_error(GError **error, const gint err_no);

gchar *comboBoxReadCleanFolderName(GtkComboBox *combobox);
gchar **strvdup(gchar **strv);
void realize_configDialog (GtkWidget *widget);
void unrealize_configDialog (GtkWidget *widget);
gchar *replaceAttributeString(gchar *rawString, const gchar *replacement);

void on_column_location_click (GtkTreeViewColumn *treeviewcolumn, gpointer user_data);
void on_column_filename_click (GtkTreeViewColumn *treeviewcolumn, gpointer user_data);
void on_column_type_click (GtkTreeViewColumn *treeviewcolumn, gpointer user_data);
void on_column_modified_click (GtkTreeViewColumn *treeviewcolumn, gpointer user_data);
void on_column_matches_click (GtkTreeViewColumn *treeviewcolumn, gpointer user_data);
void on_column_size_click (GtkTreeViewColumn *treeviewcolumn, gpointer user_data);
void columnClick(GtkWidget *widget, gint column);
void setSortMenuItem(gint columnId, GtkSortType order);
void getSortMenuItem(gint *columnId, GtkSortType *sortOrder);
gboolean SMsyscall (const gchar *address, syscallType type);
void *findExecutables(void *args);


void spawnNewSearchmonkey(void);
void importCriteria(GtkWidget *widget);
void exportCriteria(GtkWidget *widget); 

gboolean mkFullDir(gchar *folderName, gint mode);
